/*******************************************************************************
 * Copyright (c) 2014 Greg Marut.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 * 
 * Contributors:
 *    Greg Marut - initial API and implementation
 ******************************************************************************/
package com.gregmarut.serialization;

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;

import javax.imageio.ImageIO;

import com.gregmarut.util.Log;

public class SerializableImage implements Serializable
{
	// ** Finals **//
	private static final long serialVersionUID = -3683416757577905414L;
	
	// holds the format of this image
	public static final String FORMAT = "jpg";
	
	// ** Objects **//
	// holds the int array of pixels
	private byte[] aryPixels;
	
	// holds the image (not serialized)
	private transient Image objImage;
	
	/**
	 * The constructor for SerializableImage
	 * 
	 * @param objImage
	 * @throws IOException
	 */
	public SerializableImage(final Image objImage) throws IOException
	{
		this.objImage = objImage;
		
		// flatten the image down to an int array
		flattenImage();
	}
	
	/**
	 * Attempts to flatten the image
	 * 
	 * @throws InterruptedException
	 * @throws IOException
	 */
	private void flattenImage() throws IOException
	{
		ByteArrayOutputStream baosImage = new ByteArrayOutputStream();
		
		try
		{
			ImageIO.write(convertToBufferedImage(objImage), FORMAT, baosImage);
			aryPixels = baosImage.toByteArray();
		}
		finally
		{
			baosImage.flush();
			baosImage.close();
		}
	}
	
	/**
	 * Convert an image to a buffered image
	 * 
	 * @param objImage
	 * @return
	 */
	private BufferedImage convertToBufferedImage(final Image objImage)
	{
		// create a new image
		BufferedImage biReturn = new BufferedImage(
			objImage.getWidth(null),
			objImage.getHeight(null),
			BufferedImage.TYPE_INT_RGB);
		
		// draw the old image onto the buffered image
		biReturn.getGraphics().drawImage(objImage, 0, 0, null);
		
		// return the buffered image
		return biReturn;
	}
	
	/**
	 * determines if this serializable image has an image
	 * 
	 * @return
	 */
	public boolean hasImage()
	{
		return (null != aryPixels && aryPixels.length > 0);
	}
	
	/**
	 * Attempts to restore the image
	 */
	public void restoreImage()
	{
		try
		{
			ByteArrayInputStream baosImage = new ByteArrayInputStream(aryPixels);
			objImage = ImageIO.read(baosImage);
			baosImage.close();
		}
		catch (IOException IOE)
		{
			// make sure the logger should display this error
			if (Log.DISPLAY_INTERNAL_ERRORS)
			{
				// log the error
				Log.err(IOE);
			}
			
			objImage = null;
		}
	}
	
	/**
	 * Returns the image
	 * 
	 * @return
	 */
	public Image getImage()
	{
		// check to see if the image needs to be restored
		if (null == objImage && hasImage())
		{
			restoreImage();
		}
		
		return objImage;
	}
	
	/**
	 * Disposes of this image
	 */
	public void dispose()
	{
		aryPixels = null;
		objImage = null;
	}
}
